/**
 * @author Simon Richardson - me@simonrichardson.info
 */
package org.osflash.signals;

import asunit.asserts.AssertNull;
import asunit.asserts.AssertTrue;
import asunit.asserts.Fail;
import asunit.framework.IAsync;
import org.osflash.signals.events.GenericEvent;

class MonoSignalSlotTest {

	@:meta(Inject())
	public var async : IAsync;
	public var completed : MonoSignal;
	@:meta(Before())
	public function setUp() : Void {
		completed = new MonoSignal();
	}

	@:meta(After())
	public function tearDown() : Void {
		completed.removeAll();
		completed = null;
	}

	function checkGenericEvent(e : GenericEvent) : Void {
		assertNull("event.signal is not set by Signal", e.signal);
		assertNull("event.target is not set by Signal", e.target);
	}

	function newEmptyHandler() : Dynamic {
		return function() : Void {
		}
;
	}

	function failIfCalled() : Void {
		fail("This event handler should not have been called.");
	}

	//////
	@:meta(Test())
	public function add_listener_and_verify_once_is_false() : Void {
		var listener : Dynamic = newEmptyHandler();
		var slot : ISlot = completed.add(listener);
		assertTrue("Slot once is false", slot.once == false);
	}

	//////
	@:meta(Test())
	public function add_listener_and_verify_priority_is_zero() : Void {
		var listener : Dynamic = newEmptyHandler();
		var slot : ISlot = completed.add(listener);
		assertTrue("Slot priority is zero", slot.priority == 0);
	}

	//////
	@:meta(Test())
	public function add_listener_and_verify_slot_listener_is_same() : Void {
		var listener : Dynamic = newEmptyHandler();
		var slot : ISlot = completed.add(listener);
		assertTrue("Slot listener is the same as the listener", slot.listener == listener);
	}

	//////
	@:meta(Test())
	public function add_listener_and_remove_using_slot() : Void {
		var slot : ISlot = completed.add(newEmptyHandler());
		slot.remove();
		assertTrue("Number of listeners should be 0", completed.numListeners == 0);
	}

	//////
	@:meta(Test())
	public function add_listener_pause_on_slot_should_not_dispatch() : Void {
		var slot : ISlot = completed.add(failIfCalled);
		slot.enabled = false;
		completed.dispatch();
	}

	//////
	@:meta(Test())
	public function add_listener_pause_then_resume_on_slot_should_dispatch() : Void {
		var slot : ISlot = completed.add(async.add(checkGenericEvent, 10));
		slot.enabled = false;
		slot.enabled = true;
		completed.dispatch(new GenericEvent());
	}

	//////
	@:meta(Test())
	public function add_listener_switch_pause_and_resume_on_slot_should_not_dispatch() : Void {
		var slot : ISlot = completed.add(failIfCalled);
		slot.enabled = false;
		slot.enabled = true;
		slot.enabled = false;
		completed.dispatch();
	}

	//////
	@:meta(Test())
	public function add_listener_then_dispatch_change_listener_on_slot_should_dispatch_second_listener() : Void {
		var slot : ISlot = completed.add(newEmptyHandler());
		completed.dispatch();
		slot.listener = newEmptyHandler();
		completed.dispatch();
	}

	//////
	@:meta(Test())
	public function add_listener_then_dispatch_change_listener_on_slot_then_pause_should_not_dispatch_second_listener() : Void {
		var slot : ISlot = completed.add(newEmptyHandler());
		completed.dispatch();
		slot.listener = failIfCalled;
		slot.enabled = false;
		completed.dispatch();
	}

	//////
	@:meta(Test())
	public function add_listener_then_change_listener_then_switch_back_and_then_should_dispatch() : Void {
		var slot : ISlot = completed.add(newEmptyHandler());
		completed.dispatch();
		var listener : Dynamic = slot.listener;
		slot.listener = failIfCalled;
		slot.listener = listener;
		completed.dispatch();
	}

	//////
	@:meta(Test(expects="ArgumentError"))
	public function add_listener_then_set_listener_to_null_should_throw_ArgumentError() : Void {
		var slot : ISlot = completed.add(newEmptyHandler());
		slot.listener = null;
	}

	//////
	@:meta(Test())
	public function add_listener_and_call_execute_on_slot_should_call_listener() : Void {
		var slot : ISlot = completed.add(newEmptyHandler());
		slot.execute([1, 2, 3, 4, 5, 6, 7, 8, 9]);
	}

	//////
	@:meta(Test())
	public function addOnce_listener_and_verify_once_is_true() : Void {
		var listener : Dynamic = newEmptyHandler();
		var slot : ISlot = completed.addOnce(listener);
		assertTrue("Slot once is true", slot.once == true);
	}

	//////
	@:meta(Test())
	public function addOnce_listener_and_verify_priority_is_zero() : Void {
		var listener : Dynamic = newEmptyHandler();
		var slot : ISlot = completed.addOnce(listener);
		assertTrue("Slot priority is zero", slot.priority == 0);
	}

	//////
	@:meta(Test())
	public function addOnce_listener_and_verify_slot_listener_is_same() : Void {
		var listener : Dynamic = newEmptyHandler();
		var slot : ISlot = completed.addOnce(listener);
		assertTrue("Slot listener is the same as the listener", slot.listener == listener);
	}

	//////
	@:meta(Test())
	public function addOnce_listener_and_remove_using_slot() : Void {
		var slot : ISlot = completed.addOnce(newEmptyHandler());
		slot.remove();
		assertTrue("Number of listeners should be 0", completed.numListeners == 0);
	}

	//////
	@:meta(Test())
	public function addOnce_listener_pause_then_resume_on_slot_should_dispatch() : Void {
		var slot : ISlot = completed.addOnce(async.add(checkGenericEvent, 10));
		slot.enabled = false;
		slot.enabled = true;
		completed.dispatch(new GenericEvent());
	}

	//////
	@:meta(Test())
	public function addOnce_listener_switch_pause_and_resume_on_slot_should_not_dispatch() : Void {
		var slot : ISlot = completed.addOnce(failIfCalled);
		slot.enabled = false;
		slot.enabled = true;
		slot.enabled = false;
		completed.dispatch();
	}

	//////
	@:meta(Test())
	public function addOnce_listener_then_dispatch_change_listener_on_slot_should_dispatch_second_listener() : Void {
		var slot : ISlot = completed.addOnce(newEmptyHandler());
		completed.dispatch();
		slot.listener = newEmptyHandler();
		completed.dispatch();
	}

	//////
	@:meta(Test())
	public function addOnce_listener_then_dispatch_change_listener_on_slot_then_pause_should_not_dispatch_second_listener() : Void {
		var slot : ISlot = completed.addOnce(newEmptyHandler());
		completed.dispatch();
		slot.listener = failIfCalled;
		slot.enabled = false;
		completed.dispatch();
	}

	//////
	@:meta(Test())
	public function addOnce_listener_then_change_listener_then_switch_back_and_then_should_dispatch() : Void {
		var slot : ISlot = completed.addOnce(newEmptyHandler());
		completed.dispatch();
		var listener : Dynamic = slot.listener;
		slot.listener = failIfCalled;
		slot.listener = listener;
		completed.dispatch();
	}

	//////
	@:meta(Test(expects="ArgumentError"))
	public function addOnce_listener_then_set_listener_to_null_should_throw_ArgumentError() : Void {
		var slot : ISlot = completed.addOnce(newEmptyHandler());
		slot.listener = null;
	}

	//////
	@:meta(Test())
	public function addOnce_listener_and_call_execute_on_slot_should_call_listener() : Void {
		var slot : ISlot = completed.addOnce(newEmptyHandler());
		slot.execute([1, 2, 3, 4, 5, 6, 7, 8, 9]);
	}

}

